"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

from threading import Timer
from msnp.service import network
from msnp.service.network import sending, logic
from msnp.logger import Logger
from msnp.service.network.model.CustodyModel import HelloMessage, AuthMessage, \
    ShiftedPeerMessage, CustodyQueueType, GroupsReicevedMessage, \
    MemberStatusChangedMessage, ResponsibleIdentityFoundMessage, MediaContentMessage, \
    PersonalMessage, PersonalMessageCallback, \
    GetMediaContentSinceLastSynchMessage
from msnp.service import synch
from msnp.gui import MySignal
from msnp.model import PTPModel


__isDoingHello = False

#the timer instance
__kAlivetimer = None
#the interval
__timerInterval = 2
#set to True when tested once for super peer ability
__alreadyTestedForSuperpeer = False


def setIsDoingHello(doing):
    """Sets the global variable which indicates if the peer is currently in the hello phase.
    
    Args:
        doing: boolean indicating whether the current peer is currently in the hello phase.
    """
    
    global __isDoingHello
    
    __isDoingHello = doing


#################
## START_TIMER ##
#################

def startKeepAliveTimer():
    """This function starts the keep-alive timer.
    """
    
    global __kAlivetimer
    global __stop
    
    __kAlivetimer = Timer(__timerInterval, __executeKeepAlive)
    __kAlivetimer.start()

    
################
## STOP_TIMER ##
################

def stopKeepAliveTimer():
    """This function stops the keep-alive-timer."""
    
    global __kAlivetimer
    global __stop
    print "stop keep alive timer"
    
    if __kAlivetimer != None:
        __kAlivetimer.cancel()


####################
## TIMER_FINISHED ##
####################

def __executeKeepAlive():
    """This method is executed during a run of the timer.
    
    It sends a keep alive messages to the super-peer and processes the received messages.
    If the peer is still a low-level peer the timer will be restarted.
    If the keep alive was not successful and the peer is currently not in the hello phase a hello is sent."""
    
    global __isDoingHello
    isLowLevel = network.NetworkController.getMySelf().isLowLevelPeer()
    #only execute if I am still a low level peer
    if isLowLevel and __isDoingHello == False:
        responsibleSuperPeerIdentity = network.NetworkController.getMySelf().getResponsibleSuperPeer()
        if responsibleSuperPeerIdentity != None:
            #ask responsible peer for messages and process them
            (returnType, messages) = sending.Sender.sendKeepAlive(responsibleSuperPeerIdentity, CustodyQueueType.ALL_TYPES);
            if returnType == PTPModel.ReturnType.SUCCESSFUL:
                if messages != None:
                    processReceivedMessages(messages)
                isLowLevel = network.NetworkController.getMySelf().isLowLevelPeer()
                #only restart timer if I am still a low level peer
                if isLowLevel:
                    startKeepAliveTimer()
                    __testForSuperpeer()
            #responsible peer is not reachable or some error occurred there while asking for messages -> re-hello 
            else:
                if __isDoingHello == False:
                    Logger.info("keepAlive returned NOT SUCCESSFUL -> rehello")
                    startKeepAliveTimer()
                    isLogin = network.NetworkController.getMySelf().getIsLogin() or network.NetworkController.getMySelf().isAuthenticated()
                    sending.Sender.hello(isLogin, None)
        #if the responsible peer is None I re-hello
        else:
            Logger.info('responsible super peer is none in executeKeepAlive')
            startKeepAliveTimer()
            isLogin = network.NetworkController.getMySelf().getIsLogin()
            sending.Sender.hello(isLogin, None)


#####################
## PROCESS_MESSAGE ##
#####################
        
def processReceivedMessages(messages):
    """This function processes the received messages stored at the responsible super peer.
    
    Depending on the type, the message is forwarded to another function.
    
    Args:
        messages: a list of CustodyMessage instances.
    """
    
    if len(messages) > 0:
        Logger.info("got " + str(len(messages)) + " message(s)")
        for custodyMessage in messages:
            if isinstance(custodyMessage, HelloMessage):
                __processHelloMessage(custodyMessage)
            elif isinstance(custodyMessage, AuthMessage):
                __processAuthMessage(custodyMessage)
            elif isinstance(custodyMessage, ResponsibleIdentityFoundMessage):
                __processRespIdentityFoundMessage(custodyMessage)
            elif isinstance(custodyMessage, ShiftedPeerMessage):
                __processShiftedPeers(custodyMessage)
            elif isinstance(custodyMessage, GroupsReicevedMessage):
                __processGroupsReiceved(custodyMessage)
            elif isinstance(custodyMessage, MemberStatusChangedMessage):
                __processMemberStatusChanged(custodyMessage)
            elif isinstance(custodyMessage, MediaContentMessage):
                __processMediaContentMessage(custodyMessage)
            elif isinstance(custodyMessage, GetMediaContentSinceLastSynchMessage):
                __processGetMediaContentSinceLastSynch(custodyMessage)
            elif isinstance(custodyMessage, PersonalMessage):
                __processPersonalMessage(custodyMessage)
            elif isinstance(custodyMessage, PersonalMessageCallback):    
                __processPersonalMessageCallback(custodyMessage)
            else:
                Logger.info('unknown message received during keep alive')
        
        
def __processHelloMessage(helloMessage):
    """This function is executed after the reception of a hello-message.
    
    Args:
        helloMessage: a HelloMessage instance
    """
    
    global __alreadyTestedForSuperpeer
    #process message only if I am not authenticated yet
    if network.NetworkController.getMySelf().isAuthenticated() == False:
        responsibleIdentity = helloMessage.getResponsibleIdentity()
        if responsibleIdentity != None:
            Logger.info("got responsible identity: " + responsibleIdentity.getNameBundle())
            network.NetworkController.getMySelf().setResponsibleSuperPeer(responsibleIdentity)
            sending.Sender.authenticate(responsibleIdentity, helloMessage.isLogin())
            __alreadyTestedForSuperpeer = False
        else:
            errorType = None
            if helloMessage.isLogin():
                errorType = PTPModel.ReturnType.ALREADY_LOGGED_IN
                Logger.info('no responsible identity in hello message -> I am already logged in -> quit')
            else:
                errorType = PTPModel.ReturnType.REGISTER_NAME_NOT_AVAILABLE
                Logger.info('no responsible identity in hello message -> I am already registered -> quit')
            MySignal.emitAuthFinishedSignal(errorType)
    else:
        Logger.info("got a hello-message but I am already authenticated??")


def __processAuthMessage(authMessage):
    """This function is executed after the reception of an authentication message.
    
    Args:
        authMessage: a AuthMessage instance
    """
    
    authReturnType = authMessage.getAuthValidationType()
    if authReturnType == PTPModel.ReturnType.SUCCESSFUL:
        Logger.info('Authentication successful.')
        network.NetworkController.getMySelf().setAuthenticated(True)
        network.NetworkController.getMySelf().setIsLogin(True)
    else:
        Logger.info('error during authentication process. error code: ' + PTPModel.ReturnType.returnTypeToString(authReturnType))
    MySignal.emitAuthFinishedSignal(authReturnType)
        
        
def __processRespIdentityFoundMessage(respMessage):
    """This function is executed after the reception of a responsible identity found message.
    
    Args:
        respMessage: a ResponsibleIdentityFoundMessage instance
    """
    
    respIdentity = respMessage.getResponsibleIdentity()
    searchedName = respMessage.getSearchedName()
    result = respMessage.getResult()
    reactType = respMessage.getReactType()
    logic.ResponsibilityLogic.responsibleIdentityReceived(respIdentity, searchedName, result, reactType)


def __processShiftedPeers(shiftMessage):
    """This function is executed after the reception of a shifted peers message.
    
    Args:
        shiftMessage: a ShiftedPeerMessage instance
    """
    
    newResponsiblePeer = shiftMessage.getNewSuperPeer()
    Logger.info("got new responsible peer " + newResponsiblePeer.getName())
    network.NetworkController.getMySelf().setResponsibleSuperPeer(newResponsiblePeer)
        
        
def __processGroupsReiceved(groupsMessage):
    """This function is executed after the reception of a groups message.
    
    Args:
        groupsMessage: a GroupsReicevedMessage instance
    """
    
    groups = groupsMessage.getGroups()
    reactType = groupsMessage.getReactType()
    searchFinished = groupsMessage.getSearchFinished()
    logic.GroupManagementLogic.groupsReceived(groups, reactType, searchFinished)


def __processMemberStatusChanged(memberStatusMessage):
    """This function is executed after the reception of a member status change message.
    
    Args:
        memberStatusMessage: a MemberStatusChangedMessage instance
    """

    groupname = memberStatusMessage.getGroupname()
    ownername = memberStatusMessage.getOwnername()
    status = memberStatusMessage.getStatus()
    membername = memberStatusMessage.getMembername()
    processed = memberStatusMessage.isProcessed()
    logic.GroupManagementLogic.memberStatusChanged(groupname, ownername, status, membername, processed)


def __processMediaContentMessage(mediaContentMessage):
    """This function is executed after the reception of a media content message.
    
    Args:
        mediaContentMessage: a MediaContentMessage instance
    """
    
    content = mediaContentMessage.getContent()
    timestamp = mediaContentMessage.getTimestamp()
    network.NetworkLock.acquireMediaLock()
    try:
        synch.NetSynchController.receiveMediaContent(content, timestamp)
    finally:
        network.NetworkLock.releaseMediaLock()


def __processGetMediaContentSinceLastSynch(getMediaContentMessage):
    """This function is executed after the reception of a media content since last synch message message.
    
    Args:
        getMediaContentMessage: a GetMediaContentSinceLastSynchMessage instance
    """
    
    senderIdentity = getMediaContentMessage.getSenderIdentity()
    senderName = getMediaContentMessage.getSenderName()
    group = getMediaContentMessage.getGenres()
    timestamp = getMediaContentMessage.getTimestamp()
    logic.MessageExchangeLogic.sendMediaContentSinceLastSynch(senderIdentity, senderName, group, timestamp)
    
    
def __processPersonalMessage(pMessage):
    """This function is executed after the reception of a personal message.
    
    Args:
        pMessage: a PersonalMessage instance
    """

    chatMessage = PTPModel.ChatMessage(pMessage.getSendername(), pMessage.getMessage(), pMessage.getTimestamp(), PTPModel.ChatMessageStatus.RECEIVED)
    MySignal.emitChatMessageReceivedSignal(chatMessage)


def __processPersonalMessageCallback(pMsgCallback):
    """This function is executed after the reception of a personal message callback message.
    
    Args:
        pMsgCallback: a PersonalMessageCallback instance
    """
    
    MySignal.emitChatMessageStatusChangedSignal(pMsgCallback.getTimestamp(), pMsgCallback.getStatus(), pMsgCallback.getSendername())
    
    
#############################
## SUPER_PEER_ABILITY_TEST ##
#############################

def __testForSuperpeer():
    """This function is called every time the low level peer sends a keep-alive and is still a low level peer.
    
    It checks the peer's ability of being a super peer and eventually calls the superPeerAbilityTest function at the responsible peer."""
    
    global __alreadyTestedForSuperpeer
    isAuthenticated = network.NetworkController.getMySelf().isAuthenticated()
    isLowLevelPeer = network.NetworkController.getMySelf().isLowLevelPeer()
    if __alreadyTestedForSuperpeer == False and isAuthenticated and isLowLevelPeer:
        ableForSuperPeer = __checkForSuperPeerAbility()
        if ableForSuperPeer:
            sending.Sender.superPeerAbilityTest()

def __checkForSuperPeerAbility():
    """This function is designed to check the peer's ability of being a super peer.
    
    Currently there are no restrictions on the computational power, therefore the function returns True.
    
    Returns:
        True if the peer is able to become a super peer, False otherwise.
    """
    
    return True

